#-*- coding: utf-8 -*-

import serial
import time
import numpy as np
import pandas as pd
import json
from matplotlib import pyplot as plt
plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签
plt.rcParams['axes.unicode_minus']=False #用来正常显示负号

ser = serial.Serial('COM11', 9600, parity=serial.PARITY_NONE, bytesize=serial.EIGHTBITS, stopbits=serial.STOPBITS_ONE)

lpData = {'I_A': 0x0260, 'I_B': 0x0262, 'I_C': 0x0264, 'I_N': 0x0266, 'I_G': 0x0268,
          'I_R': 0x0269, 'Ui_A': 0x0276, 'Ui_B': 0x0277, 'Ui_C': 0x0278, 'Uo_A': 0x0279,
          'Uo_B': 0x027A, 'Uo_C': 0x027B, 'Ue': 0x027C, 'Fu_A': 0x027E, 'Fu_B': 0x027F,
          'Fu_C': 0x0280, 'PhaSeq': 0x0281, 'ImbalanceRatioOfU': 0x02B5,
          'ImbalanceRatioOfI': 0x02B6, 'InTemperature': 0x02B7, 'InHumdity': 0x02B8,
          'TemperatureOfBusbar_A': 0x02B9, 'TemperatureOfBusbar_B': 0x02BA,
          'TemperatureOfBusbar_C': 0x02BB}
lpData_message = \
        {'I_A':[0x03,0x03,0x02,0x60,0x00,0x02,0xC4,0x4F],
        'I_B':[0x03,0x03,0x02,0x62,0x00,0x02,0x65,0x8F],
        'I_C':[0x03,0x03,0x02,0x64,0x00,0x02,0x85,0x8E],
        'I_N':[0x03,0x03,0x02,0x66,0x00,0x02,0x24,0x4E],
        'I_G':[0x03,0x03,0x02,0x68,0x00,0x01,0x05,0x8C],
        'I_R':[0x03,0x03,0x02,0x69,0x00,0x01,0x54,0x5C],
        'Ui_A':[0x03,0x03,0x02,0x76,0x00,0x01,0x65,0x8A],
        'Ui_B':[0x03,0x03,0x02,0x77,0x00,0x01,0x34,0x4A],
        'Ui_C':[0x03,0x03,0x02,0x78,0x00,0x01,0x04,0x49],
        'Uo_A':[0x03,0x03,0x02,0x79,0x00,0x01,0x55,0x89],
        'Uo_B':[0x03,0x03,0x02,0x7A,0x00,0x01,0xA5,0x89],
        'Uo_C':[0x03,0x03,0x02,0x7B,0x00,0x01,0xF4,0x49],
        'Ue':[0x03,0x03,0x02,0x7C,0x00,0x01,0x45,0x88],
        'Fu_A':[0x03,0x03,0x02,0x7E,0x00,0x01,0xE4,0x48],
        'Fu_B':[0x03,0x03,0x02,0x7F,0x00,0x01,0xB5,0x88],
        'Fu_C':[0x03,0x03,0x02,0x80,0x00,0x01,0x85,0xB8],
        'PhaSeq':[0x03,0x03,0x02,0x81,0x00,0x01,0xD4,0x78],
        'ImbalanceRatioOfU':[0x03,0x03,0x02,0xB5,0x00,0x01,0x95,0xB6],
        'ImbalanceRatioOfI':[0x03,0x03,0x02,0xB6,0x00,0x01,0x65,0xB6],
        'InTemperature':[0x03,0x03,0x02,0xB7,0x00,0x01,0x34,0x76],
        'InHumdity':[0x03,0x03,0x02,0xB8,0x00,0x01,0x04,0x75],
        'TemperatureOfBusbar_A':[0x03,0x03,0x02,0xB9,0x00,0x01,0x55,0xB5],
        'TemperatureOfBusbar_B':[0x03,0x03,0x02,0xBA,0x00,0x01,0xA5,0xB5],
        'TemperatureOfBusbar_C':[0x03,0x03,0x02,0xBB,0x00,0x01,0xF4,0x75]}

HpData_message = \
        {'I_A':[0x03, 0x03, 0x02, 0xE0, 0x00, 0x01, 0x85, 0xA6],
        'I_B':[0x03,0x03,0x02,0xE1,0x00,0x01,0xD4,0x66],
        'I_C':[0x03,0x03,0x02,0xE2,0x00,0x01,0x24,0x66],
        'U_A':[0x00,0x03,0x02,0xE3,0x00,0x01,0x75,0x95],
        'U_B':[0x03,0x03,0x02,0xE4,0x00,0x01,0xC4,0x67],
        'U_C':[0x03,0x03,0x02,0xE5,0x00,0x01,0x95,0xA7],
        'P':[0x03,0x03,0x02,0xE6,0x00,0x01,0x65,0xA7],
        'P_A':[0x03,0x03,0x02,0xE7,0x00,0x01,0x34,0x67],
        'P_B':[0x03,0x03,0x02,0xE8,0x00,0x01,0x04,0x64],
        'P_C':[0x03,0x03,0x02,0xE9,0x00,0x01,0x55,0xA4],
        'PowerFactor':[0x03,0x03,0x02,0xEA,0x00,0x01,0xA5,0xA4],
        'PowerFactor_A':[0x03,0x03,0x02,0xEB,0x00,0x01,0xF4,0x64],
        'PowerFactor_B':[0x03,0x03,0x02,0xEC,0x00,0x01,0x45,0xA5],
        'PowerFactor_C':[0x03,0x03,0x02,0xED,0x00,0x01,0x14,0x65],
        'q_PositiveActive':[0x03,0x03,0x02,0xEE,0x00,0x02,0xA4,0x64],
        'q_NegativeActive':[0x03,0x03,0x02,0xF0,0x00,0x02,0xC4,0x62],
        'q_PositiveActive_A':[0x03,0x03,0x02,0xF2,0x00,0x02,0x65,0xA2],
        'q_NegativeActive_A':[0x03,0x03,0x02,0xF4,0x00,0x02,0x85,0xA3],
        'q_PositiveActive_B':[0x03,0x03,0x02,0xF6,0x00,0x02,0x24,0x63],
        'q_NegativeActive_B':[0x03,0x03,0x02,0xF8,0x00,0x02,0x45,0xA0],
        'q_PositiveActive_C':[0x03,0x03,0x02,0xFA,0x00,0x02,0xE4,0x60],
        'q_NegativeActive_C':[0x03,0x03,0x02,0x60,0x00,0x02,0x04,0x61]}

HpData = {'I_A': 0x02E0, 'I_B': 0x02E1, 'I_C': 0x02E2, 'U_A': 0x02E3, 'U_B': 0x02E4,
          'U-C': 0x02E5, 'P': 0x02E6, 'P_A': 0x02E7, 'P_B': 0x02E8, 'P_C': 0x02E9,
          'PowerFactor': 0x02EA, 'PowerFactor_A': 0x02EB, 'PowerFactor_B': 0x02EC,
          'PowerFactor_C': 0x02ED, 'q_PositiveActive': 0x02EE,
          'q_NegativeActive': 0x02F0, 'q_PositiveActive_A': 0x02F2,
          'q_NegativeActive_A': 0x02F4, 'q_PositiveActive_B': 0x02F6,
          'q_NegativeActive_B': 0x02F8, 'q_PositiveActive_C': 0x02FA,
          'q_NegativeActive_C': 0x02FC}
lpUnits = {'I_A': 'A', 'I_B': 'A', 'I_C': 'A', 'I_N': 'A', 'I_G': 'A', 'I_R': 'mA',
           'Ui_A': 'V', 'Ui_B': 'V', 'Ui_C': 'V', 'Uo_A': 'V', 'Uo_B': 'V', 'Uo_C': 'V',
           'Ue': 'V', 'Fu_A': 'Hz', 'Fu_B': 'Hz', 'Fu_C': 'Hz', 'PhaSeq': ' ',
           'ImbalanceRatioOfU': '%', 'ImbalanceRatioOfI': '%', 'InTemperature': '℃',
           'InHumdity': '%', 'TemperatureOfBusbar_A': '℃', 'TemperatureOfBusbar_B': '℃',
           'TemperatureOfBusbar_C': '℃'}
HpUnits = {'I_A': 'A', 'I_B': 'A', 'I_C': 'A', 'U_A': 'V', 'U_B': 'V', 'U-C': 'V', 'P': 'kW',
           'P_A': 'kW', 'P_B': 'kW', 'P_C': 'kW', 'PowerFactor': ' ', 'PowerFactor_A': ' ',
           'PowerFactor_B': ' ', 'PowerFactor_C': ' ', 'q_PositiveActive': 'kWh',
           'q_NegativeActive': 'kWh', 'q_PositiveActive_A': 'kWh',
           'q_NegativeActive_A': 'kWh', 'q_PositiveActive_B': 'kWh',
           'q_NegativeActive_B': 'kWh', 'q_PositiveActive_C': 'kWh',
           'q_NegativeActive_C': 'kWh'}
if ser.is_open:
    print('串口已经打开')


# CRC-16-MODBUS
def calculate_crc16(data: bytes) -> int:
    # 初始化crc为0xFFFF
    crc = 0xFFFF

    # 循环处理每个数据字节
    for byte in data:
        # 将每个数据字节与crc进行异或操作
        crc ^= byte

        # 对crc的每一位进行处理
        for _ in range(8):
            # 如果最低位为1，则右移一位并执行异或0xA001操作(即0x8005按位颠倒后的结果)
            if crc & 0x0001:
                crc = (crc >> 1) ^ 0xA001
            # 如果最低位为0，则仅将crc右移一位
            else:
                crc = crc >> 1

    # 返回最终的crc值
    return crc


def get_data_to_send(address, num):
    data = [0x03, 0x03]
    address_high = address // 256
    address_low = address % 256
    num_high = num // 256
    num_low = num % 256
    data.append(address_high)
    data.append(address_low)
    data.append(num_high)
    data.append(num_low)
    crc = calculate_crc16(data)
    # print(data)
    crc_high = crc // 256
    crc_low = crc % 256
    data.append(crc_low)
    data.append(crc_high)
    return data


def get_data_to_receive():

    address = ser.read(1)
    function_code = ser.read(1)
    data_length = ser.read(1)
    packets = [address, function_code, data_length]
    length = int.from_bytes(data_length, byteorder='little', signed=False)
    #带校验位检测
    # data_ten = 0
    # for i in range(length):
    #     data_byte = ser.read(1)
    #     packets.append(data_byte)
    #     data_ten = data_ten * 256 + int.from_bytes(data_byte, 'big')
    # data = data_ten / 10
    # a = b''
    # c = a.join(packets)
    # crc = calculate_crc16(c)
    # crc_high = crc // 256
    # crc_low = crc % 256
    # crc_low_test = int.from_bytes(ser.read(1), 'big')
    # crc_high_test = int.from_bytes(ser.read(1), 'big')
    # if not ((crc_low_test == crc_low) and (crc_high_test == crc_high)):
    #     print("error")
    #不带校验位检测
    data_bytes = ser.read(length)
    data_ten = int.from_bytes(data_bytes, 'big')
    data = data_ten / 10
    ser.read(1)
    ser.read(1)
    return data


def get_address(group, par):
    if group == 'HpData':
        address = HpData[par]
    if group == 'lpData':
        address = lpData[par]
    return address


def get_num(group, par):
    if group == 'lpData':
        if (par == 'I_A') or (par == 'I_B') or (par == 'I_C') or (par == 'I_N'):
            return 2
    else:
        return 1


def get_units(group, par):
    if group == 'HpData':
        units = HpUnits[par]
    if group == 'lpData':
        units = lpUnits[par]
    return units


def set_process(group, par):
    global pare
    global data_to_send
    global unit
    pare = par
    data_to_send = get_message(group, par)
    unit = get_units(group, par)
    return data_to_send

def get_message(group, par):
    if group == 'HpData':
        message = HpData_message[par]
    if group == 'lpData':
        message = lpData_message[par]
    return message

def process(group, par):
    data_to_send1 = get_message(group, par)
    ser.write(bytes(data_to_send1))
    data = get_data_to_receive()
    units = get_units(group, par)
    print("The value of %s is %.1f %s" % (par, data, units))
    return data


# data_test=get_data('HpData','P_A')
# print(data_test)

def process_test():
    # ser.write(bytes(get_address('HpData','P_A')))
    ser.write(bytes(data_to_send))
    ser.read(1)
    ser.read(1)
    ser.read(1)
    data_byte = ser.read(2)
    ser.read(1)
    ser.read(1)
    data_hex = hex(int.from_bytes(data_byte, 'big'))[2:]
    data_ten = int(data_hex, 16)
    data = data_ten / 10
    print(data)
    return data

def write_dict(name_of_txt,dic):
    with open(name_of_txt, 'w') as f:
        json_str = json.dumps(dic, indent=0)
        f.write(json_str)
        f.write('\n')
def read_dict(name_of_txt):
    dict_temp = {}
    with open(name_of_txt, 'r') as f:
        for line in f.readlines():
            line = line.strip('\"\n,')
            line = line.split('\": ')
            if len(line) == 2:
                key = float(line[0])
                value = float(line[1])
                dict_temp[key] = value
    return dict_temp

xs = 240
cnt = xs
set_process('HpData', 'U_A')
# data_to_send = [0x03 ,0x03 ,0x02 ,0x5f ,0x00 ,0x01 ,0xb4 ,0x42]
# print(data_to_send)
y = []
t = []
time_start = time.time()
while cnt > 0:
    time.sleep(0.457)
    y.append(process('HpData', 'U_A'))
    t.append(round((time.time()-time_start),2))
    cnt = cnt - 1
    # time.sleep(0.001)
time_end = time.time()
freq = xs/(time_end - time_start)
print('The frequency of the process is {} Hz'.format(freq))
# print(y)
# print(t)
ser.close()
fig=plt.figure(figsize=(5,4))
plt.title('测量数据'+pare+'暂态变化曲线')  # 设置标题
plt.plot(t,y,alpha = 0.5,marker='o',markersize=5)
y_label = pare + ' / ' + unit
plt.xlabel('运行时间 / s',fontsize=10,rotation=0)
plt.ylabel(y_label,fontsize=10,rotation=0,horizontalalignment='right')
plt.ylim(0)
plt.show()
# 设置tight bbox
# load='test_computer'
# str_of_load='data_of_'+load
# fig.savefig(str_of_load+'.png', bbox_inches='tight')
dic1 = dict(zip(t,y))

# write_dict(str_of_load+'.txt',dic1)
# dic2 = read_dict('data_of_kettle.txt')
series1 = pd.Series(dic1)
series1.to_csv(f'voltage_data{int(1000*time.time())}.csv')